package org.ddevil.data;

import java.util.ConcurrentModificationException;
import java.util.Iterator;


/**
 * A lightweight implementation of Data.
 * Uses a simple array backing.
 * Usefull when you need a simple Data object to represent
 * only a few pieces of data and it isn't going to have much mutation.
 *
 * @author Rich O'Connell
 */
public class LightweightAttributes extends AbstractData implements Data {

    /**
	 *
	 */
	private static final long serialVersionUID = 5900976773593470273L;
	Attribute[] attribs;

    public LightweightAttributes(){
        this(new Attribute[]{});
    }

    /**
     *
     */
    public LightweightAttributes(String id, Object value) {
        this(new Attribute(id, value));
    }

    public LightweightAttributes(String[] ids, Object[] values) {
        this(makeDataItemArray(ids, values));
    }

    private static Attribute[] makeDataItemArray(String[] ids, Object[] vals){
        Attribute[] ret = new Attribute[ids.length];
        for(int i = 0; i < ids.length; i++){
            ret[i] = new Attribute(ids[i], vals[i]);
        }
        return ret;
    }

    public LightweightAttributes(Attribute item) {
        this(new Attribute[]{item});
    }

    public LightweightAttributes(Attribute[] items) {
        if(items.length > 0){
            //doing it this way is necessary to avoid duplicate keys
            attribs = new Attribute[]{items[0]};
            for(int i = 1; i < items.length; i++){
                addDataItem(items[i]);
            }
        }else{
            attribs = new Attribute[0];
        }
    }


    /* (non-Javadoc)
     * @see org.ddevil.data.Data#contains(java.lang.String)
     */
    public boolean contains(String dbIdentifier) {
        for(Attribute i : attribs){
            if(i.getId().equals(dbIdentifier))
                return true;
        }
        return false;
    }

    /* (non-Javadoc)
     * @see org.ddevil.data.Data#getDataItem(java.lang.String)
     */
    public Attribute getDataItem(String dbIdentifier) {
        for(Attribute i : attribs){
            if(i.getId().equals(dbIdentifier))
                return i;
        }
        return null;
    }

    /* (non-Javadoc)
     * @see org.ddevil.data.Data#getValue(java.lang.String)
     */
    public Object getValue(String dbIdentifier) {
        Attribute i = getDataItem(dbIdentifier);
        return i != null ? i.getValue() : null;
    }


    /**
     * {@inheritDoc}
     */
    public void addDataItem(Attribute toAdd) {
        boolean contains = false;
        for(Attribute i : attribs){
            if(i.getId().equals(toAdd.getId())){
                contains = true;
                i.setValue(toAdd.getValue());
                break;
            }
        }
        if(!contains){
            Attribute[] newAttribs = new Attribute[attribs.length + 1];
            System.arraycopy(attribs, 0, newAttribs, 0, attribs.length);
            newAttribs[attribs.length] = toAdd;
            attribs = newAttribs;
        }

    }

    /**
     * {@inheritDoc}
     */
    public void setDataItem(String dbId, Object newValue) {
        addDataItem(new Attribute(dbId, newValue));
    }


    public void removeDataItem(String dbId) {
        if(contains(dbId)){
            Attribute[] newAttr = new Attribute[attribs.length - 1];
            int newi = 0;
            for(int i = 0; i < attribs.length; i++){
                if(!attribs[i].getId().equals(dbId)){
                    newAttr[newi] = attribs[i];
                    newi++;
                }
            }
            attribs = newAttr;
        }

    }

    /**
     * {@inheritDoc}
     */
    public int size() {
        return attribs.length;
    }

    /* (non-Javadoc)
     * @see java.lang.Iterable#iterator()
     */
    public Iterator<Attribute> iterator() {
        return new Iterator<Attribute>(){
            int i = 0;
            int check = attribs.length;

            public boolean hasNext() {
                if(attribs.length != check)
                    throw new ConcurrentModificationException();
                return i < attribs.length;
            }

            public Attribute next() {
                if(attribs.length != check)
                    throw new ConcurrentModificationException();
                return attribs[i++];
            }

            public void remove() {
                throw new UnsupportedOperationException("If you want "
                        + getClass().getSimpleName()
                        + "'s Iterator to support remove then implement it.");
            }
        };
    }

}
